package com.cloud.springcloudhysyrix.consumer;

import com.cloud.springcloudhysyrix.hebingqingqiu.WxmBatchCommand;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixRequestCache;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import rx.Observable;
import rx.Observer;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * weiximei on 2018/5/1
 */
@RestController
public class ConsumerController {

    /**  这里注释掉，因为没有实现高可用！  **/

    /**
     * 引入 Ribbon组件 进行客户端的负载均衡的类
     */
//    @Autowired
//    private LoadBalancerClient loadBalancerClient;
//
//    @RequestMapping("/consumer")
//    public String hellorConsumer(){
//        // stores.ribbon.listOfServers=localhost:8082,localhost:8081
//        // 这里的值是我们自定义 stores，但是上面的ribbon.listOfServers是定死的
//        // 经过 LoadBalancerClient 的均衡算法（默认轮询算法），会给出集群中的一个客户端的URI，
//        ServiceInstance serviceInstance = loadBalancerClient.choose("stores");
//        // http://%s:%s 是一个语法，$s会被替成相应的内容
//        URI url = URI.create(String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort()));
//
//        return url.toString();
//    }


    /** Ribbon和Eureka注册中心对接后，实现高可用的获取服务列表的地址 **/


//    @Autowired
//    private RestTemplate restTemplate;
//
//    @RequestMapping("/consumer")
//    public String ribbonConsumer(){
//        // 获取这个服务，并把结果返回出去
//        // 请求 HELLO-SERVICE 服务中心，然后就会获取到 HELLO-SERVICE 服务上注册好的客户端列表,
//        // 然后根据这个列表进行均很负载算法得到一个Eureka客户端的连接
//        return restTemplate.getForEntity("http://HELLO-SERVICE/hello",String.class).getBody();
//    }


    /** 这里演示整合Hystrix 请求熔断处理 **/
    @Autowired
    private HelloService helloService;

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/consumer")
    public String ribbonConsumer(){
        /**
         * 方法一：这个方式是注解方式实现的
         */
        // 将上面的方法进行改写
        //return helloService.helloService();

        /**
         * 方法二：这个方式是手动实现的
         *      command.execute(); 堵塞式IO执行
         *      command.execute(); 非堵塞式IO执行
         */
//        HelloServiceCommand command = new HelloServiceCommand("hello",restTemplate);
          // 执行execute方法。也就是执行HelloServiceCommand里面的run方法
          // 使用堵塞式IO执行
//        String result = command.execute();
//
          //非堵塞式IO
//        Future<String> future = command.queue();
//        return future.get();

//        return result; // 堵塞方式返回

        /**
         * 方法三：使用观察者模式
         *
         *      下面的冷执行和热执行模式。
         *      热执行就是不等你 observe.subscribe() 方法是事件注册完，就直接开始执行观察者模式里面的业务。
         *      冷执行就是等着 observe.subscribe() 方法的事件注册完毕，然后在开始执行观察者模式里面的业务。
         *
         */
        List<String> list = new ArrayList<>();
        HelloServiceObserveCommand command1 = new HelloServiceObserveCommand("hello",restTemplate);
        // 冷执行方式
        // command1.toObservable();
        // 执行请求方法，热执行方式
        Observable observe = command1.observe();
        observe.subscribe(new Observer<String>() {
            @Override
            public void onCompleted() {
                System.out.println("聚合完成了所以请求");
            }

            @Override
            public void onError(Throwable e) {
                // 出现异常
                e.printStackTrace();
            }

            @Override
            public void onNext(String o) {
                // 把数据添加到List
                list.add(o);
            }
        });

        return list.toString();

    }



    /**       请求缓存演示       **/

    @RequestMapping("/cosumerCache")
    public String helloConsumerCache(){

        // 初始化 Hystrix 请求上下文环境。
        HystrixRequestContext.initializeContext();
        HelloServiceCommandCache commandCache = new HelloServiceCommandCache("hello",restTemplate);
        // 使用同步方法模式执行,也就是堵塞式IO
        commandCache.execute();

        // 清除缓存
        // commandGroupKey 的key一定要相同。
        // 清除的key要和getCacheKey()返回的key相同。
        HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey("hello")
                                        ,HystrixConcurrencyStrategyDefault.getInstance())
                                        .clear("hello");



        return null;
    }




    /**        演示请求合并        **/
    @RequestMapping("/consumer")
    public String helloConsumer() throws ExecutionException, InterruptedException {

        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        // 创建合并请求
        // 这里只创建三个的原因是，控制器里面只返回3条结果
        WxmBatchCommand wxmBatchCommand1 = new WxmBatchCommand(1L,restTemplate);
        WxmBatchCommand wxmBatchCommand2 = new WxmBatchCommand(2L,restTemplate);
        WxmBatchCommand wxmBatchCommand3 = new WxmBatchCommand(3L,restTemplate);

        //使用非堵塞式IO
        Future<String> future1 = wxmBatchCommand1.queue();
        Future<String> future2 = wxmBatchCommand2.queue();

        String r1 = future1.get();
        String r2 = future2.get();

        // 睡2000毫秒
        Thread.sleep(2000);

        Future<String> future3 = wxmBatchCommand3.queue();
        String r3 = future3.get();

        System.out.println(r1);
        System.out.println(r2);
        System.out.println(r3);

        context.close();

        return null;
    }



}
